import { extend, hasChange, isArray, isIntegerKey, isObject } from './../common/utils';
import { reactive } from './reactive';
import { track, trigger } from './effect';
import { TrackOpTypes } from './operators';
import { TriggerOpTypes } from '@vue/reactivity';
// mutableHandlers中存在get和set 
// createGetter拦截获取功能
function createGetter(isReadonly = false, shallow = false) {
  return function get(target, key, receiver) {
    /*
    *（1）proxy+reflect: 两者搭配同时使用，去proxy取值，会通过reflect把target返回给；
    *（2）后续Object上的方法 都会被迁移到Reflect上；
    *（3）之前在set中通过target[key]=value是存在问题的，因为这种方法可能会设置值失败，但并没有报错也不会有返回值标识；
    *（4）Reflect方法具备返回值，赋值结果有误的时候，会返回报错；
    */
    const res = Reflect.get(target, key, receiver);
    if (!isReadonly) {
      // 如果isReadonly不是只读的，需要收集依赖，等数据变化时更新视图
      track(target, TrackOpTypes.GET, key);
    }
    if (isObject(res)) {
      //vue2中进入页面就会对所有的data进行递归遍历，并添加getter和setter,
      //但是vue3是只有在取值的时候，再回去做代理，所以vue3中的代理也称为懒代理。这就很好的提高了性能
      // res是对象
      return !isReadonly && reactive(res);
    }
    return res;
  }
}
// createSetter拦截设置功能
function createSetter(shallow = false) {
  return function set(target, key, value, receiver) {
    let oldValue = target[key]; //获取老值
    /*
    *判读是数组时 数组中是否存在key
    *判断是对象时，是否在target上存在该属性
    */
    let hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasChange(target, key);
    const result = Reflect.set(target, key, value, receiver);
    if (!hadKey) {
      // 新增
      trigger(target, TriggerOpTypes.ADD, key, value)
    } else if (hasChange(oldValue, value)) {
      // 更新
      trigger(target, TriggerOpTypes.SET, key, value, oldValue)
    }
    return result;
  }
}
const get = createGetter();
const set = createSetter();
export const mutableHandlers = {
  get,
  set
}